/*
 *  (C) Copyright 2008 Insula Tecnologia da Informacao Ltda.
 * 
 *  This file is part of Vulcano.
 *
 *  Vulcano is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Vulcano is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with Vulcano.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.openinsula.vulcano.orm.command.transaction.operations;

import java.util.Collection;
import java.util.List;

import org.openinsula.vulcano.core.command.Command;
import org.openinsula.vulcano.core.command.transaction.TransactionInvoker;
import org.openinsula.vulcano.orm.command.DaoCommandFactory;
import org.openinsula.vulcano.orm.command.DaoCommandFactory.TransactionCommand;
import org.openinsula.vulcano.orm.command.transaction.InitializeCallback;
import org.openinsula.vulcano.orm.dao.query.DaoQuery;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.Assert;

/**
 * @author Eduardo R Danielli
 *
 */
public class DaoCommandTransactionOperationsDelegate implements DaoCommandTransactionOperations {

	private final PlatformTransactionManager transactionManager;

	private final TransactionInvoker transactionInvoker;
	
	private final DaoCommandFactory commandFactory;
	
	/**
	 * Uses transactionInvoker's default TransactionManager
	 * @param transactionInvoker required
	 * @param commandFactory required
	 */
	public DaoCommandTransactionOperationsDelegate(final TransactionInvoker transactionInvoker, final DaoCommandFactory commandFactory) {
		this(null, transactionInvoker, commandFactory);
	}
	
	public DaoCommandTransactionOperationsDelegate(final PlatformTransactionManager transactionManager, final TransactionInvoker transactionInvoker, final DaoCommandFactory commandFactory) {
		Assert.notNull(transactionInvoker, "TransactionInvoker required!");
		Assert.notNull(commandFactory, "DaoCommandFactory required!");
		
		this.transactionManager = transactionManager;
		this.transactionInvoker = transactionInvoker;
		this.commandFactory = commandFactory;
	}

	public final <T> T invoke(final Command<T> command) {
		return transactionInvoker.invoke(command, transactionManager);
	}
	
	public <T> T findById(final Class<T> entityClass, final Object id) {
		return invoke(commandFactory.createFindByIdCommand(entityClass, id));
	}
	
	@Override
	public <T> T findById(final InitializeCallback<T> initializeCallback, final Class<T> entityClass, final Object id) {
		TransactionCommand<T> command = commandFactory.createFindByIdCommand(entityClass, id);
		command.setInitializeCallback(initializeCallback);
		return invoke(command);
	}
	
	public <T> List<T> listAll(final Class<T> entityClass) {
		return invoke(commandFactory.createListAllCommand(entityClass));
	}
	
	@Override
	public <T> List<T> listAll(final InitializeCallback<List<T>> initializeCallback, final Class<T> entityClass) {
		TransactionCommand<List<T>> command = commandFactory.createListAllCommand(entityClass);
		command.setInitializeCallback(initializeCallback);
		return invoke(command);
	}
	
	public <T> List<T> find(final String queryString, final Object... values) {
		return invoke(commandFactory.<T>createFindCommand(queryString, values));
	}
	
	@Override
	public <T> List<T> find(final InitializeCallback<List<T>> initializeCallback, final String queryString, final Object... values) {
		TransactionCommand<List<T>> command = commandFactory.<T>createFindCommand(queryString, values);
		command.setInitializeCallback(initializeCallback);
		return invoke(command);
	}
	
	public <T> int save(final T... entities) {
		return invoke(commandFactory.createSaveCommand(entities));
	}
	
	public int saveAll(final Collection<?> entities) {
		return invoke(commandFactory.createSaveCollectionCommand(entities));
	}
	
	@Override
	public <T> T merge(final T entity) {
		return invoke(commandFactory.createMergeCommand(entity));
	}
	
	public <T> int delete(final T... entities) {
		return invoke(commandFactory.createDeleteCommand(entities));
	}
	
	public int deleteAll(final Collection<?> entities) {
		return invoke(commandFactory.createDeleteCollectionCommand(entities));
	}
	
	public int deleteAll(final Class<?> entityClass) {
		return invoke(commandFactory.createDeleteTypeCommand(entityClass));
	}
	
	public int update(final String queryString, final Object... values) {
		return invoke(commandFactory.createUpdateCommand(queryString, values));
	}
	
	public void refresh(final Object entity) {
		invoke(commandFactory.createRefreshCommand(entity));
	}
	
	@Override
	public <T> void refresh(final InitializeCallback<T> initializeCallback, final T entity) {
		TransactionCommand<T> command = commandFactory.createRefreshCommand(entity);
		command.setInitializeCallback(initializeCallback);
		invoke(command);
	}
	
	public void reattach(final Object entity) {
		invoke(commandFactory.createReattachCommand(entity));
	}
	
	@Override
	public <T> void reattach(final InitializeCallback<T> initializeCallback, final T entity) {
		TransactionCommand<T> command = commandFactory.createReattachCommand(entity);
		command.setInitializeCallback(initializeCallback);
		invoke(command);		
	}

	@Override
	public <T> List<T> find(final DaoQuery daoQuery) {
		return invoke(commandFactory.<T>createFindCommand(daoQuery));
	}
	
	@Override
	public <T> List<T> find(final InitializeCallback<List<T>> initializeCallback, final DaoQuery daoQuery) {
		TransactionCommand<List<T>> command = commandFactory.<T>createFindCommand(daoQuery);
		command.setInitializeCallback(initializeCallback);
		return invoke(command);
	}

	@Override
	public <T> T findUnique(final DaoQuery daoQuery) {
		return invoke(commandFactory.<T>createFindUniqueCommand(daoQuery));
	}
	
	@Override
	public <T> T findUnique(final InitializeCallback<T> initializeCallback, final DaoQuery daoQuery) {
		TransactionCommand<T> command = commandFactory.<T>createFindUniqueCommand(daoQuery);
		command.setInitializeCallback(initializeCallback);
		return invoke(command);
	}

	@Override
	public <T> T findUnique(final String queryString, final Object... values) {
		return invoke(commandFactory.<T>createFindUniqueCommand(queryString, values));
	}
	
	@Override
	public <T> T findUnique(final InitializeCallback<T> initializeCallback, final String queryString, final Object... values) {
		TransactionCommand<T> command = commandFactory.<T>createFindUniqueCommand(queryString, values);
		command.setInitializeCallback(initializeCallback);
		return invoke(command);
	}

}
